﻿using System;
using Tao.OpenGl;

namespace Aeon.Framework.Objects.Models.ModelBVH
{

/// <summary>
/// BVH class for operation and display.
/// 
/// </summary>
public sealed class AdapterBVH : IPlayAdapter
    {
    // --- Attributes:

    private short direction;    // Direction flags. 0 for paused, + forward, - backward.
    private ushort channel;     // Frame based channel counter.
    private ushort frame;       // Current frame.
    private ushort end;         // Final frame.
    private ushort beg;         // Start frame.

    private Boolean loop;       // Loop flag.
    private DataBVH motion;     // Motion data.

    // --- Properties:

    public Boolean Loop { get { return(loop); } set { loop = value; } }
    public Single Percent { get { return(((float)frame/end)*100F); } }

    // --- Constructor:

    public AdapterBVH(DataBVH datafile)
        {
        motion = datafile;

        loop = false;
        direction = 0;
        frame = beg = 0;
        end = (ushort)(motion.Motion.Frames-1);
        }

    // --- Internal Methods:

    /// <summary>
    /// Recurses through Joint tree and updates Limb position.
    /// 
    /// </summary>
    private void move(Joint joint)
        {
        Position jpos = joint.Position;
        Orientation jrot = Orientation.Origin;

        Gl.glPushMatrix();

        if (!joint.Root)
            {
            // Limb Line:
            Gl.glColor4f(AeonColors.Purple.R,AeonColors.Purple.G,AeonColors.Purple.B,1.0f);

            Gl.glBegin(Gl.GL_LINES);
            Gl.glVertex3d(0,0,0);
            Gl.glVertex3d(jpos.xPos,jpos.yPos,jpos.zPos);
            Gl.glEnd();
            }

        for(int ch=0; ch<joint.Channels; ch++)
            {
            Single val = motion.Motion.getData(frame,channel++);
            Channel chan = joint.getChannel(ch);
            
            switch(chan.Type)
                {
                case(Channels.Xpos): jpos.Transform(new VectorC(val,0,0)); break;
                case(Channels.Ypos): jpos.Transform(new VectorC(0,val,0)); break;
                case(Channels.Zpos): jpos.Transform(new VectorC(0,0,val)); break;

                case(Channels.Xrot): jrot.Transform(new Orientation(val,0,0)); break;
                case(Channels.Yrot): jrot.Transform(new Orientation(0,val,0)); break;
                case(Channels.Zrot): jrot.Transform(new Orientation(0,0,val)); break;
                }
            }

        Gl.glTranslatef(jpos.xPos,jpos.yPos,jpos.zPos);
        Gl.glRotatef(jrot.zAng,0,0,1);
        Gl.glRotatef(jrot.xAng,1,0,0);
        Gl.glRotatef(jrot.yAng,0,1,0);
        
        // Joint Sphere:
        if (joint.Root) { Gl.glColor4f(AeonColors.Red.R,AeonColors.Red.G,AeonColors.Red.B,1.0f); }
        else { Gl.glColor4f(AeonColors.Purple.R,AeonColors.Purple.G,AeonColors.Purple.B,1.0f); }

        Glu.GLUquadric quadric = Glu.gluNewQuadric();
        Glu.gluQuadricDrawStyle(quadric, Glu.GLU_FILL);
        Glu.gluQuadricNormals(quadric, Glu.GLU_SMOOTH);
        Glu.gluSphere(quadric, 1, 10, 10);
        Glu.gluDeleteQuadric(quadric);

        int children = joint.Children;
        for(int cnt=0;cnt<children;cnt++) { move(joint.getChild(cnt)); }

        Gl.glPopMatrix();
        }

    // --- Public Methods:

    public void AnimateStop() { frame = beg; AnimatePause(); }
    public void AnimateEnd() { frame = end; AnimatePause(); }
    public void AnimateBackward() { direction = -1; }
    public void AnimateForward() { direction = 1; }
    public void AnimatePause() { direction = 0; }
    public void AnimateLoop() { loop = !loop; }

    public void Draw()
        {
        if (direction>0) { if (frame==end) { if (loop) frame = beg; } else frame++; }
        if (direction<0) { if (frame==beg) { if (loop) frame = end; } else frame--; }

        channel = 0;
        move(motion.Root);
        }

    public override string ToString()
        {
        return(motion.ToString());
        }

    }


}